package com.sojson.util.security.shiro.interceptor.impl;

import java.io.IOException;
import java.lang.annotation.Annotation;

import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.aop.AuthorizingAnnotationHandler;
import org.apache.shiro.subject.Subject;

import com.sojson.config.exception.TransErrorCode;
import com.sojson.config.exception.TransNoException;
import com.sojson.constant.ConstantByMap;
import com.sojson.util.filter.FilterUtil;
import com.sojson.util.security.shiro.annotation.RequiredPermission;
import com.sojson.util.servlet.ServletUtil;

/**
 * 权限注解实际处理类
 * 
 * @author liu
 * @date 2020-11-02
 */
public class RequiredPermissionAnnotationHandler extends AuthorizingAnnotationHandler {

    public RequiredPermissionAnnotationHandler() {
        // 告诉shiro这个处理器处理哪个注解
        super(RequiredPermission.class);
    }

    /**
     * 获取注解中value的所有值
     * 
     * @param a
     * @return
     */
    protected String[] getAnnotationValue(Annotation a) {
        RequiredPermission rpAnnotation = (RequiredPermission)a;
        return rpAnnotation.value();
    }

    /**
     * 主要方法
     */
    @Override
    public void assertAuthorized(Annotation a) throws AuthorizationException {
        // 方法上的注解是否是这个注解,如果不是就不做处理
        if (!(a instanceof RequiredPermission)) {
            return;
        }

        RequiredPermission rpAnnotation = (RequiredPermission)a;
        // 获取注解中的所有权限
        String[] perms = getAnnotationValue(a);
        Subject subject = getSubject();
        // 如果注解中只有一个value就只判断一个
        if (perms.length == 1) {
            // 如不包含果注解中的权限就抛异常
            if (!subject.isPermitted(perms[0])) {
                try {
                    if (subject.isAuthenticated()) {
                        FilterUtil.responseDate(ServletUtil.getHttpServletRequest(),
                            ServletUtil.getHttpServletResponse(), TransErrorCode.NOT_PERM_PERMISSION,
                            ConstantByMap.CONTROLLER_URL_OPEN_UNAUTHORIZED_URL_ALL);
                    } else {
                        FilterUtil.responseDate(ServletUtil.getHttpServletRequest(),
                            ServletUtil.getHttpServletResponse(), TransErrorCode.NOT_LOGIN,
                            ConstantByMap.CONTROLLER_URL_OPEN_LOGIN_URL_ALL);
                    }
                } catch (IOException e) {
                }
                throw new TransNoException();
            }
            return;
        }

        // 多个权限是并且关系
        if (Logical.AND.equals(rpAnnotation.logical())) {
            // 如果注解中的所有权限都不包含就抛异常
            if (!subject.isPermittedAll(perms)) {
                try {
                    if (subject.isAuthenticated()) {
                        FilterUtil.responseDate(ServletUtil.getHttpServletRequest(),
                            ServletUtil.getHttpServletResponse(), TransErrorCode.NOT_PERM_PERMISSION,
                            ConstantByMap.CONTROLLER_URL_OPEN_UNAUTHORIZED_URL);
                    } else {
                        FilterUtil.responseDate(ServletUtil.getHttpServletRequest(),
                            ServletUtil.getHttpServletResponse(), TransErrorCode.NOT_LOGIN,
                            ConstantByMap.CONTROLLER_URL_OPEN_LOGIN_URL);
                    }
                } catch (IOException e) {
                }
                throw new TransNoException();
            }
            return;
        }

        // 多个权限是或者关系
        if (Logical.OR.equals(rpAnnotation.logical())) {
            // 定义是否包含某个权限
            boolean hasAtLeastOnePermission = false;
            // 遍历注解中的所有权限
            for (String permission : perms) {
                // 有一个是true就通过
                if (subject.isPermitted(permission)) {
                    hasAtLeastOnePermission = true;
                    break;
                }
            }
            // 如果不包含任意一个权限就抛异常
            if (!hasAtLeastOnePermission) {
                try {
                    if (subject.isAuthenticated()) {
                        FilterUtil.responseDate(ServletUtil.getHttpServletRequest(),
                            ServletUtil.getHttpServletResponse(), TransErrorCode.NOT_PERM_PERMISSION,
                            ConstantByMap.CONTROLLER_URL_OPEN_UNAUTHORIZED_URL);
                    } else {
                        FilterUtil.responseDate(ServletUtil.getHttpServletRequest(),
                            ServletUtil.getHttpServletResponse(), TransErrorCode.NOT_LOGIN,
                            ConstantByMap.CONTROLLER_URL_OPEN_LOGIN_URL);
                    }
                } catch (IOException e) {
                }
                throw new TransNoException();
            }
        }
    }

}
